package org.summerframework.web.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 异步方法
 *
 * <p>
 * 自定义线程池
 * {@link AsyncConfigurer}
 * asyncExecutor
 */
@Configuration
@EnableAsync
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Slf4j
public class ExecutorConfiguration {
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @ConditionalOnMissingBean(AsyncConfigurer.class)
    public AsyncConfigurer asyncConfigurer() {
        return new AsyncConfigurer() {
            @Override
            public Executor getAsyncExecutor() {
//                if (asyncExecutor != null) {
//                    return asyncExecutor;
//                }
                ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
                //配置核心线程数
                executor.setCorePoolSize(10);
                //配置最大线程数
                executor.setMaxPoolSize(10);
                //配置队列大小
                executor.setQueueCapacity(99999);
                //配置线程池中的线程的名称前缀
                executor.setThreadNamePrefix("async-service-thread-");

                // rejection-policy：当pool已经达到max size的时候，如何处理新任务
                // CALLER_RUNS：不在新线程中执行任务，而是有调用者所在的线程来执行
                executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
                executor.initialize();

                return executor;
            }

            @Override
            public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
                return (ex, method, args) -> {
                    log.warn("执行异常 {}", method.getName(), ex);
                };
            }
        };
    }
}
